#pragma once

#include <cstdint>
#include <stdexcept>
#include <string>

namespace ibox::network {

class IpAddress {
public:
    struct FormatInvalid : public std::runtime_error {
        explicit FormatInvalid(const std::string &str)
            : std::runtime_error(Format(str)) {}
        static std::string Format(const std::string &str);
    };

    explicit IpAddress(uint32_t ip = 0) : m_ip(ip) {}

    IpAddress &operator=(uint32_t ip) {
        m_ip = ip;
        return *this;
    }
    inline explicit operator uint32_t() const { return m_ip; }
    inline explicit operator std::string() const { return to_string(); }

    IpAddress operator~() const { return IpAddress(~m_ip); }
    IpAddress operator&(const IpAddress &rhs) const {
        return IpAddress(m_ip & rhs.m_ip);
    }
    IpAddress operator|(const IpAddress &rhs) const {
        return IpAddress(m_ip | rhs.m_ip);
    }

    bool operator==(const IpAddress &rhs) const { return m_ip == rhs.m_ip; }

    std::string to_string() const;

public:
    /// 将字串转换成IpAddress
    /**
     * \param   ip_str      字串
     * \return  IpAddress
     *
     * \throw   FormatInvalid   字串格式不对
     */
    static IpAddress from_string(const std::string &ip_str);

    static IpAddress any();  // 0.0.0.0
    static IpAddress loop(); // 127.0.0.1

private:
    uint32_t m_ip;
};
} // namespace ibox::network
